package com.xf.system.utils.redis;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author xiefengf
 */
@Aspect
@Component
@Slf4j
public class RedisAspect {

    @Resource
    private RedissonClient redissonClient;

    @Pointcut(value = "@annotation(com.xf.system.utils.redis.RedisLock)")
    public void pointcut() {
    }

    /**
     * 环绕通知
     * @param pjp
     * @return
     */
    @Around(value = "pointcut() && @annotation(redisLock)")
    public Object myAround(ProceedingJoinPoint pjp,RedisLock redisLock) {
        // 获取key
        String lockKey = redisLock.lockKey();
        // 获取锁
        RLock lock = redissonClient.getLock(lockKey);

        String methodName = pjp.getSignature().getName();
        Object[] args = pjp.getArgs();
        Object proceed = null;
        boolean tryLock = false;
        try {
            //尝试加锁,最大等待1秒尝试获取锁，获得锁后600秒自动释放锁
            if (lock.tryLock(1, 600, TimeUnit.SECONDS)) {
                // 睡眠一秒 防止释放锁的时间过快 被其他线程抢到
                Thread.sleep(1100);
                //就是利用反射调用目标方法即可，就是 method.invoke(obj, args)
//                log.info("获取锁成功:{}", lockKey);
                proceed = pjp.proceed(args);
                lock.unlock();
            }else {
//                log.info("获取锁失败:{}", lockKey);
                return proceed;
            }
        } catch (Exception e) {
            // 解锁
            lock.unlock();
            throw new RuntimeException(e);
        } catch (Throwable throwable) {
            // 解锁
            lock.unlock();
            throwable.printStackTrace();
        } finally {
//            if (tryLock){
//                // 解锁
//                lock.unlock();
//            }
//            log.info("释放分布式锁[{}]", lockKey);
        }
        //反射调用后的返回值也一定返回出去，不返回会空指针
        return proceed;
    }





//    @Around(value = "pointcut()")
//    public Object myAround(ProceedingJoinPoint pjp) {
//        /**
//         * 定义锁
//         */
//        RLock lock = redissonClient.getLock(LOCK_KEY);
//
//        String methodName = pjp.getSignature().getName();
//        Object[] args = pjp.getArgs();
//        Object proceed = null;
//        try {
//            //@Before
//            System.out.println("【环绕前置通知】---"+ methodName +"---【方法开始】");
//            //就是利用反射调用目标方法即可，就是 method.invoke(obj, args)
//            proceed = pjp.proceed(args);
//            //@AfterReturning
//            System.out.println("【环绕返回通知】---"+ methodName +"---【方法返回，返回值 "+ proceed +"】");
//        } catch (Exception e) {
//            //@AfterThrowing
//            System.out.println("【环绕异常通知】---"+ methodName +"---【方法出现异常】，异常信息：" + e);
//            //为了让外界能知道这个异常，这个异常一定要抛出去
//            throw new RuntimeException(e);
//        } catch (Throwable throwable) {
//            throwable.printStackTrace();
//        } finally {
//            //@After
//            System.out.println("【环绕后置通知】---"+ methodName +"---【方法结束】");
//        }
//        //反射调用后的返回值也一定返回出去，不返回会空指针
//        return proceed;
//    }

}
